#include <stdio.h>
#include <string.h>
#include <netinet/ip.h>

int main(int argc, char *argv[])
{
    int fd;
    struct sockaddr_in addr;
    char s[] = 
{0x45,0x00,0x03,0xeb,0xa5,0xe3,0x40,0x00,0x80,0x06,0xf5,0xae,0xc0,0xa8,0x01,0x79,
 0x7b,0x7d,0x1d,0xdc,0x0f,0x07,0x00,0x50,0x5d,0x0d,0xa6,0x1e,0x41,0x0d,0x71,0x3c,
 0x50,0x18,0x80,0x00,0x5f,0x58,0x00,0x00,0x47,0x45,0x54,0x20,0x2f,0x6e,0x65,0x77,
 0x69,0x6d,0x70,0x72,0x65,0x73,0x73,0x3f,0x61,0x64,0x75,0x6e,0x69,0x74,0x69,0x64,
 0x3d,0x50,0x44,0x50,0x53,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x35,0x32,0x31,0x31,
 0x36,0x26,0x72,0x6f,0x74,0x61,0x74,0x65,0x5f,0x63,0x6f,0x75,0x6e,0x74,0x3d,0x31,
 0x30,0x26,0x54,0x49,0x4d,0x45,0x53,0x54,0x41,0x4d,0x50,0x3d,0x69,0x34,0x61,0x79,
 0x62,0x76,0x34,0x39,0x26,0x72,0x65,0x66,0x65,0x72,0x72,0x61,0x6c,0x3d,0x68,0x74,
 0x74,0x70,0x25,0x33,0x41,0x25,0x32,0x46,0x25,0x32,0x46,0x77,0x77,0x77,0x2e,0x73,
 0x69,0x6e,0x61,0x2e,0x63,0x6f,0x6d,0x2e,0x63,0x6e,0x25,0x32,0x46,0x26,0x63,0x61,
 0x6c,0x6c,0x62,0x61,0x63,0x6b,0x3d,0x5f,0x73,0x69,0x6e,0x61,0x61,0x64,0x73,0x5f,
 0x63,0x62,0x73,0x5f,0x6b,0x64,0x69,0x70,0x62,0x35,0x20,0x48,0x54,0x54,0x50,0x2f,
 0x31,0x2e,0x31,0x0d,0x0a,0x48,0x6f,0x73,0x74,0x3a,0x20,0x73,0x61,0x78,0x2e,0x73,
 0x69,0x6e,0x61,0x2e,0x63,0x6f,0x6d,0x2e,0x63,0x6e,0x0d,0x0a,0x43,0x6f,0x6e,0x6e,
 0x65,0x63,0x74,0x69,0x6f,0x6e,0x3a,0x20,0x6b,0x65,0x65,0x70,0x2d,0x61,0x6c,0x69,
 0x76,0x65,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,0x3a,0x20,0x2a,0x2f,0x2a,0x0d,
 0x0a,0x55,0x73,0x65,0x72,0x2d,0x41,0x67,0x65,0x6e,0x74,0x3a,0x20,0x4d,0x6f,0x7a,
 0x69,0x6c,0x6c,0x61,0x2f,0x35,0x2e,0x30,0x20,0x28,0x57,0x69,0x6e,0x64,0x6f,0x77,
 0x73,0x20,0x4e,0x54,0x20,0x35,0x2e,0x31,0x29,0x20,0x41,0x70,0x70,0x6c,0x65,0x57,
 0x65,0x62,0x4b,0x69,0x74,0x2f,0x35,0x33,0x37,0x2e,0x33,0x36,0x20,0x28,0x4b,0x48,
 0x54,0x4d,0x4c,0x2c,0x20,0x6c,0x69,0x6b,0x65,0x20,0x47,0x65,0x63,0x6b,0x6f,0x29,
 0x20,0x43,0x68,0x72,0x6f,0x6d,0x65,0x2f,0x33,0x36,0x2e,0x30,0x2e,0x31,0x39,0x38,
 0x35,0x2e,0x31,0x32,0x35,0x20,0x53,0x61,0x66,0x61,0x72,0x69,0x2f,0x35,0x33,0x37,
 0x2e,0x33,0x36,0x0d,0x0a,0x52,0x65,0x66,0x65,0x72,0x65,0x72,0x3a,0x20,0x68,0x74,
 0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x73,0x69,0x6e,0x61,0x2e,0x63,0x6f,
 0x6d,0x2e,0x63,0x6e,0x2f,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,0x74,0x2d,0x45,0x6e,
 0x63,0x6f,0x64,0x69,0x6e,0x67,0x3a,0x20,0x67,0x7a,0x69,0x70,0x2c,0x64,0x65,0x66,
 0x6c,0x61,0x74,0x65,0x2c,0x73,0x64,0x63,0x68,0x0d,0x0a,0x41,0x63,0x63,0x65,0x70,
 0x74,0x2d,0x4c,0x61,0x6e,0x67,0x75,0x61,0x67,0x65,0x3a,0x20,0x7a,0x68,0x2d,0x43,
 0x4e,0x2c,0x7a,0x68,0x3b,0x71,0x3d,0x30,0x2e,0x38,0x2c,0x65,0x6e,0x3b,0x71,0x3d,
 0x30,0x2e,0x36,0x0d,0x0a,0x43,0x6f,0x6f,0x6b,0x69,0x65,0x3a,0x20,0x53,0x49,0x4e,
 0x41,0x47,0x4c,0x4f,0x42,0x41,0x4c,0x3d,0x32,0x32,0x31,0x2e,0x36,0x2e,0x31,0x35,
 0x2e,0x31,0x34,0x36,0x5f,0x31,0x33,0x37,0x36,0x33,0x35,0x38,0x32,0x30,0x38,0x2e,
 0x34,0x36,0x30,0x35,0x37,0x37,0x3b,0x20,0x55,0x5f,0x54,0x52,0x53,0x31,0x3d,0x30,
 0x30,0x30,0x30,0x30,0x30,0x39,0x32,0x2e,0x62,0x63,0x39,0x30,0x36,0x36,0x65,0x2e,
 0x35,0x32,0x30,0x39,0x38,0x66,0x37,0x36,0x2e,0x66,0x32,0x64,0x64,0x33,0x64,0x64,
 0x65,0x3b,0x20,0x76,0x6a,0x75,0x69,0x64,0x73,0x3d,0x32,0x34,0x39,0x34,0x65,0x66,
 0x38,0x66,0x33,0x2e,0x31,0x34,0x30,0x61,0x33,0x65,0x31,0x39,0x64,0x61,0x61,0x2e,
 0x30,0x2e,0x61,0x62,0x34,0x66,0x36,0x36,0x66,0x63,0x3b,0x20,0x5f,0x5f,0x75,0x74,
 0x6d,0x61,0x3d,0x32,0x36,0x39,0x38,0x34,0x39,0x32,0x30,0x33,0x2e,0x33,0x30,0x32,
 0x37,0x31,0x33,0x36,0x2e,0x31,0x33,0x37,0x37,0x31,0x33,0x39,0x31,0x30,0x37,0x2e,
 0x31,0x33,0x37,0x37,0x31,0x33,0x39,0x31,0x30,0x37,0x2e,0x31,0x33,0x38,0x39,0x36,
 0x30,0x30,0x37,0x35,0x32,0x2e,0x32,0x3b,0x20,0x53,0x47,0x55,0x49,0x44,0x3d,0x31,
 0x33,0x37,0x37,0x31,0x33,0x39,0x30,0x30,0x38,0x31,0x39,0x36,0x5f,0x38,0x37,0x33,
 0x34,0x30,0x39,0x38,0x36,0x3b,0x20,0x53,0x55,0x42,0x3d,0x41,0x56,0x6f,0x39,0x35,
 0x38,0x65,0x32,0x31,0x6b,0x49,0x53,0x76,0x6c,0x33,0x6a,0x6f,0x42,0x49,0x51,0x55,
 0x48,0x71,0x59,0x68,0x31,0x5a,0x74,0x76,0x35,0x77,0x37,0x50,0x56,0x6f,0x76,0x71,
 0x67,0x76,0x30,0x4a,0x46,0x5a,0x74,0x64,0x71,0x52,0x4d,0x30,0x4e,0x37,0x6e,0x69,
 0x58,0x48,0x77,0x71,0x42,0x4f,0x36,0x64,0x69,0x36,0x50,0x6b,0x37,0x54,0x44,0x63,
 0x48,0x48,0x6c,0x4e,0x64,0x6f,0x4f,0x68,0x67,0x75,0x67,0x5a,0x62,0x4d,0x75,0x65,
 0x4f,0x48,0x35,0x4e,0x45,0x53,0x6f,0x42,0x6e,0x45,0x65,0x4d,0x76,0x51,0x54,0x39,
 0x7a,0x42,0x7a,0x6f,0x4c,0x50,0x64,0x75,0x70,0x76,0x5a,0x25,0x32,0x46,0x56,0x6a,
 0x78,0x70,0x66,0x67,0x77,0x54,0x42,0x67,0x55,0x58,0x45,0x79,0x51,0x49,0x4c,0x69,
 0x71,0x25,0x32,0x46,0x70,0x78,0x6c,0x32,0x47,0x6c,0x65,0x44,0x45,0x32,0x68,0x72,
 0x36,0x4e,0x52,0x5a,0x53,0x45,0x25,0x33,0x44,0x3b,0x20,0x53,0x55,0x42,0x50,0x3d,
 0x30,0x30,0x32,0x41,0x32,0x63,0x2d,0x67,0x56,0x6c,0x77,0x45,0x6d,0x31,0x64,0x41,
 0x57,0x78,0x66,0x67,0x58,0x45,0x4c,0x75,0x75,0x75,0x4c,0x62,0x57,0x39,0x55,0x70,
 0x48,0x53,0x39,0x70,0x57,0x35,0x2d,0x30,0x38,0x63,0x42,0x62,0x48,0x31,0x71,0x67,
 0x52,0x6e,0x7a,0x3b,0x20,0x55,0x4f,0x52,0x3d,0x2c,0x2c,0x3b,0x20,0x55,0x4c,0x56,
 0x3d,0x31,0x34,0x31,0x39,0x39,0x32,0x34,0x34,0x30,0x34,0x33,0x37,0x36,0x3a,0x31,
 0x39,0x3a,0x31,0x3a,0x31,0x3a,0x3a,0x31,0x34,0x30,0x36,0x36,0x31,0x39,0x36,0x34,
 0x32,0x37,0x37,0x32,0x3b,0x20,0x76,0x6a,0x6c,0x61,0x73,0x74,0x3d,0x31,0x34,0x31,
 0x39,0x39,0x32,0x34,0x34,0x30,0x35,0x0d,0x0a,0x0d,0x0a};
    int rc;
    long pkt_limit = 0;
    long fail = 0;
    long i, j;
    int speed;
    struct timeval start_tv, tv;
    long div = 400;
    long pps;
    long Bps;
    long pkt_sent;
    long pkt_next;
    long batch;
    long total_pkt_sent = 0;
    long timediff;
    long timediff_expect;
    long div_duration = 1000000 / div;

    if (argc < 3)
    {
        printf("usage: %s 192.168.1.25 81\n", argv[0]);
        return 1;
    }
    if (argc >= 4)
    {
        pkt_limit = atoi(argv[3]);
    }
    else
    {
        pkt_limit = 0x7ffffffe;
    }
    if (argc >= 5)
    {
        Bps = atoi(argv[4]) * 1024 * 1024;
    }
    else
    {
        Bps = 0x7ffffffe;
    }
    pps = Bps / sizeof(s);

    batch = pps / div;

    fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));

    while (total_pkt_sent < pkt_limit)
    {
        pkt_sent = 0;
        gettimeofday(&start_tv, NULL);
        while (1)
        {
            rc = sendto(fd, s, sizeof(s), 0, (struct sockaddr*)&addr, sizeof(addr));
            if (rc != sizeof(s))
            {
                fail++;
            }
            pkt_sent++;
            total_pkt_sent++;
            if (pkt_sent == pps || total_pkt_sent == pkt_limit)
            {
                goto show_status;
            }

            if (pkt_sent % batch == 0)
            {
                gettimeofday(&tv, NULL);
                timediff = (tv.tv_sec - start_tv.tv_sec) * 1000000 + tv.tv_usec - start_tv.tv_usec;
                timediff_expect = pkt_sent * 1000000 / pps;
                if (timediff < timediff_expect)
                {
                    //printf("usleep %ld\n", timediff_expect - timediff);
                    usleep(timediff_expect - timediff);
                }
            }
        }

show_status:        
        gettimeofday(&tv, NULL);
        timediff = ((tv.tv_sec - start_tv.tv_sec) * 1000000 + tv.tv_usec - start_tv.tv_usec);
        printf("packets %10ld  send fail %4ld  speed %.1f MB/s timediff %ld us\n", 
            total_pkt_sent, fail, pkt_sent * sizeof(s) * 1000000.0 / (1024L * 1024 * timediff), timediff);
    }
    
    close(fd);

    return 0;
}

